
open Common

module type BASE =
sig
  type t
  val compare : t -> t -> int
  val default : t
  val to_string : t -> string
end

module type T =
sig
  include BASE
  val lt : t -> t -> bool
  val le : t -> t -> bool
  val gt : t -> t -> bool
  val ge : t -> t -> bool
  val eq : t -> t -> bool
  val neq : t -> t -> bool
  val max : t -> t -> t
  val maxl : t list -> t
  val min : t -> t -> t
  val minl : t list -> t

  module Ops : 
  sig
    val ( < ) : t -> t -> bool
    val ( <= ) : t -> t -> bool
    val ( > ) : t -> t -> bool
    val ( >= ) : t -> t -> bool
    val ( = ) : t -> t -> bool
    val ( <> ) : t -> t -> bool
  end
end

module S(B : BASE) : T with type t = B.t =
struct 
  include B
  let lt x y = compare x y < 0
  let eq x y = compare x y = 0
  let gt x y = compare x y > 0
  let le x y = lt x y || eq x y
  let ge = c le
  let neq x y = not (eq x y)

  module Ops = 
  struct 
    let ( < ) x y = lt x y
    let ( <= ) x y = le x y
    let ( > ) x y = gt x y
    let ( >= ) x y = ge x y
    let ( = ) x y = eq x y
    let ( <> ) x y = neq x y
  end

  open Ops

  let max x y = if x < y then y else x
  let maxl l = foldr_end max l
  let min x y = if x < y then x else y
  let minl l = foldr_end min l

end

module IntBase : BASE with type t = int = 
struct 
  type t = int
  let default = 0
  let compare = compare
  let to_string = string_of_int 
end
module Int : T with type t = int = S(IntBase)

module StringBase : BASE with type t = string = 
struct 
  type t = string
  let default = ""
  let compare = compare
  let to_string = id
end
module String : T with type t = string = S(StringBase)

module FloatBase : BASE with type t = float = 
struct 
  type t = float
  let default = 0.0
  let compare = compare
  let to_string = string_of_float  
end
module Float : T with type t = float = S(FloatBase)
